﻿using Microsoft.Devices;
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using ZXing;

namespace BarCodeScannerControl.Controls
{
    public partial class BarCodeScannerControl : UserControl, IScanner
    {
        private PhotoCamera phoneCamera;
        private IBarcodeReader barcodeReader;
        private DispatcherTimer scanTimer;
        private WriteableBitmap previewBuffer;

        public BarCodeScannerControl()
        {
            InitializeComponent();
        }

        #region Vibrate Property
        
        public bool VibrateEnabled
        {
            get
            {
                return (bool)GetValue(VibrateEnabledProperty);
            }
            set
            {
                SetValue(VibrateEnabledProperty, value);
            }
        }
        
        // Using a DependencyProperty as the backing store for VibrateEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty VibrateEnabledProperty =
            DependencyProperty.Register("VibrateEnabled", typeof(bool), typeof(BarCodeScannerControl), new PropertyMetadata(true));
        
        #endregion
        
        public void StartScan()
        {
            phoneCamera = new PhotoCamera();
            phoneCamera.Initialized -= PhoneCameraInitialized;
            phoneCamera.Initialized += PhoneCameraInitialized;
            
            CameraButtons.ShutterKeyHalfPressed -= CameraButtons_ShutterKeyHalfPressed;
            CameraButtons.ShutterKeyHalfPressed += CameraButtons_ShutterKeyHalfPressed;

            viewfinderBrush.SetSource(phoneCamera);
            
            scanTimer = new DispatcherTimer();
            scanTimer.Interval = TimeSpan.FromMilliseconds(250);
            scanTimer.Tick -= (o, arg) => ScanForBarcode();
            scanTimer.Tick += (o, arg) => ScanForBarcode();
        }

        public void StopScan()
        {
            try
            {
                phoneCamera.Dispose();
                scanTimer.Stop();
                
            }
            catch (Exception)
            {
            }
        }

        public void Pause()
        {
            if (scanTimer.IsEnabled)
            {
                scanTimer.Stop();
            }
        }

        public void Resume()
        {
            scanTimer.Start();
        }
        void CameraButtons_ShutterKeyHalfPressed(object sender, System.EventArgs e)
        {
            if (phoneCamera != null && phoneCamera.IsFocusSupported)
            {
                phoneCamera.Focus();
            }
        }
        
        void PhoneCameraInitialized(object sender, CameraOperationCompletedEventArgs e)
        {
            if (e.Succeeded)
            {
                this.Dispatcher.BeginInvoke(() =>
                {
                    try
                    {
                        phoneCamera.FlashMode = FlashMode.Off;
                        previewBuffer = new WriteableBitmap((int)phoneCamera.PreviewResolution.Width,(int)phoneCamera.PreviewResolution.Height);
                        barcodeReader = new BarcodeReader();
                        barcodeReader.TryHarder = true;
                        barcodeReader.ResultFound -= BarcodeReaderResultFound;
                        barcodeReader.ResultFound += BarcodeReaderResultFound;
                        scanTimer.Start();
                        RaiseScannerInitialized(true);
                    }
                    catch (Exception ex)
                    {
                        RaiseScannerInitialized(false, ex);
                    }
                });
            }
            else
            {
                Dispatcher.BeginInvoke(() =>
                {
                    RaiseScannerInitialized(false, e.Exception);
                });
            }
        }
        
        void BarcodeReaderResultFound(Result obj)
        {
            if (!string.IsNullOrEmpty(obj.Text))
            {
                this.Dispatcher.BeginInvoke(() =>
                {
                    if (VibrateEnabled)
                        VibrateController.Default.Start(TimeSpan.FromMilliseconds(100));
                
                    RaiseScannerReadCompleted(obj.Text);
                });
            }
        }
        
        private void ScanForBarcode()
        {
            phoneCamera.GetPreviewBufferArgb32(previewBuffer.Pixels);
            previewBuffer.Invalidate();
        
            barcodeReader.Decode(previewBuffer);
        }
        
        private void viewFinder_Tap(object sender, System.Windows.Input.GestureEventArgs e)
        {
            if (phoneCamera != null && phoneCamera.IsFocusSupported)
            {
                phoneCamera.Focus();
            }
        }

        public event EventHandler<Events.ReadScannerCompleted> OnReadScannerCompleted;

        public event EventHandler<Events.ScannerInitialized> OnScannerInitialized;
        
        private void RaiseScannerInitialized(bool isInitialized, Exception error=null)
        {
            if (OnScannerInitialized != null)
            {
                OnScannerInitialized.Invoke(this, new Events.ScannerInitialized(isInitialized, error));
            }
        }
        
        private void RaiseScannerReadCompleted(string result, Exception error = null)
        {
            if (OnReadScannerCompleted != null)
            {
                this.OnReadScannerCompleted.Invoke(this, new Events.ReadScannerCompleted(result, error));
            }
        }
    }
}